package com.guandi.geekbrowser.primary.service.impl;

import com.guandi.geekbrowser.primary.entity.Ipool;
import com.guandi.geekbrowser.primary.repository.IpoolRepository;
import com.guandi.geekbrowser.primary.service.IpoolService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.*;
import java.util.List;

@Service
public class IpoolServiceImpl implements IpoolService {

    @Autowired
    IpoolRepository ipoolRepository;

    @Override
    public List<Ipool> findByUserIdAndUsestatus(String id, Integer use) {
        return ipoolRepository.findByUserIdAndUsestatus(id, use);
    }

    @Override
    public Ipool saveIpool(Ipool ipool) {
        return ipoolRepository.save(ipool);
    }

    @Override
    public List<Ipool> saveAll(List<Ipool> ipools) {
        return ipoolRepository.saveAll(ipools);
    }

    @Override
    public List<Ipool> findAll() {
        return ipoolRepository.findAll();
    }

    @Override
    public Ipool findByUserIdAndAddressAndPort(String id, String address, String port) {
        return ipoolRepository.findByUserIdAndAddressAndPort(id, address, port);
    }

    @Override
    public List<Ipool> findByUserIdAndUsestatusAndTypeOrderByPortAsc(String id, Integer use, Integer type) {
        return ipoolRepository.findByUserIdAndUsestatusAndTypeOrderByPortAsc(id, use, type);
    }

    @Override
    public Ipool findByAddressAndPort(String address, String port) {
        return ipoolRepository.findByAddressAndPort(address, port);
    }

    @Override
    public Ipool findByAddressAndPortAndUserId(String address, String port, String userId) {
        return ipoolRepository.findByAddressAndPortAndUserId(address, port, userId);
    }

    @Override
    public List<Ipool> findByUserIdAndUsestatusAndType(String id, Integer use, Integer type) {
        return ipoolRepository.findByUserIdAndUsestatusAndType(id, use, type);
    }

    @Override
    public Integer updateType(Long id, Integer type) {
        return ipoolRepository.updateType(id, type);
    }

    @Override
    public Integer updateUsestatus(Long id, Integer usestatus) {
        return ipoolRepository.updateUsestatus(id, usestatus);
    }

    @Override
    public List<Ipool> findByUserIdAndType(String id, Integer type) {
        return ipoolRepository.findByUserIdAndType(id, type);
    }

    @Override
    public Page<Ipool> findByUserIdAndTypePage(String id, Integer type, int pageSize, int pageNumber) {
        Pageable pageable = PageRequest.of(pageNumber - 1, pageSize);
        Specification<Ipool> spe = new Specification<Ipool>() {
            @Override
            public Predicate toPredicate(Root<Ipool> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<String> userIdStr = root.get("userId");
                Path<Integer> typeInteger = root.get("type");
                Predicate typePre = criteriaBuilder.equal(typeInteger, type);
                Predicate userIdPre = criteriaBuilder.equal(userIdStr, id);
                Predicate pre = criteriaBuilder.and(typePre, userIdPre);
                return pre;
            }
        };
        return ipoolRepository.findAll(spe, pageable);
    }

    @Override
    public Page<Ipool> findByUserIdAndTypeAndCountryPage(String id, Integer type, int pageSize, int pageNumber, String country) {
        Pageable pageable = PageRequest.of(pageNumber - 1, pageSize);
        Specification<Ipool> spe = new Specification<Ipool>() {
            @Override
            public Predicate toPredicate(Root<Ipool> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<String> userIdStr = root.get("userId");
                Path<String> countryPath = root.get("country");
                Path<Integer> typeInteger = root.get("type");
                Predicate typePre = criteriaBuilder.equal(typeInteger, type);
                Predicate userIdPre = criteriaBuilder.equal(userIdStr, id);
                Predicate countryPre = criteriaBuilder.equal(countryPath, country);
                Predicate pre = criteriaBuilder.and(typePre, userIdPre, countryPre);
                return pre;
            }
        };
        return ipoolRepository.findAll(spe, pageable);
    }

    @Override
    public Ipool findByUserIdAndId(String userId, Long id) {
        return ipoolRepository.findByUserIdAndId(userId, id);
    }

    @Override
    public void deleteByIdAndUserId(Long id, String userId) {
        ipoolRepository.deleteByIdAndUserId(id, userId);
    }

    @Override
    public List<Ipool> findByUserIdAndUsestatusAndCountry(String id, Integer use, String country) {
        return ipoolRepository.findByUserIdAndUsestatusAndCountry(id, use, country);
    }

    @Override
    public Ipool findByAddressAndPortAndUserIdAndCountry(String address, String port, String userId, String country) {
        return ipoolRepository.findByAddressAndPortAndUserIdAndCountry(address, port, userId, country);
    }

    @Override
    public Page<Ipool> findByUserIdUseStatusTypeCountryBindOrderByPortASCPage(String userId, Integer use, Integer bind, Integer type, String country) {
        Pageable pageable = PageRequest.of(0, 1);
        Specification<Ipool> spe = new Specification<Ipool>() {
            @Override
            public Predicate toPredicate(Root<Ipool> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<String> userIdPath = root.get("userId");
                Path<Integer> usestatusPath = root.get("usestatus");
                Path<String> countryPath = root.get("country");
                Path<Integer> bindPath = root.get("bind");
                Path<Integer> typePath = root.get("type");
                Predicate userIdPre = criteriaBuilder.equal(userIdPath, userId);
                Predicate typePre = criteriaBuilder.equal(typePath, type);
                Predicate bindPre = criteriaBuilder.equal(bindPath, bind);
                Predicate usestatusPre = criteriaBuilder.equal(usestatusPath, use);
                Predicate countryPre = criteriaBuilder.equal(countryPath, country);
                Predicate pre = criteriaBuilder.and(typePre, userIdPre, countryPre, bindPre, usestatusPre);
                return pre;
            }
        };
        long qty = ipoolRepository.findAll(spe, pageable).getTotalElements();
        if (qty == 0) {
            qty = 1L;
        }
        int idx = (int) (Math.random() * qty);

        int page = idx - 1;
        if (page < 0) {
            page = 0;
        }
        pageable = PageRequest.of(page, 1);
        return ipoolRepository.findAll(spe, pageable);
    }

    @Override
    public List<Ipool> findByUserIdUseStatusTypeCountryBindOrderByPortASC(String userId, Integer use, Integer bind, Integer type, String country) {
        Specification<Ipool> spe = new Specification<Ipool>() {
            @Override
            public Predicate toPredicate(Root<Ipool> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<String> userIdPath = root.get("userId");
                Path<Integer> usestatusPath = root.get("usestatus");
                Path<String> countryPath = root.get("country");
                Path<Integer> bindPath = root.get("bind");
                Path<Integer> typePath = root.get("type");
                Predicate userIdPre = criteriaBuilder.equal(userIdPath, userId);
                Predicate typePre = criteriaBuilder.equal(typePath, type);
                Predicate bindPre = criteriaBuilder.equal(bindPath, bind);
                Predicate usestatusPre = criteriaBuilder.equal(usestatusPath, use);
                Predicate countryPre = criteriaBuilder.equal(countryPath, country);
                criteriaQuery.orderBy(criteriaBuilder.asc(root.get("port")));
                Predicate pre = criteriaBuilder.and(typePre, userIdPre, countryPre, bindPre, usestatusPre);
                return pre;
            }
        };
        return ipoolRepository.findAll(spe);
    }

    @Override
    public Ipool findByUserIdAndTypeQuery(String userId, Integer type) {
        return ipoolRepository.findByUserIdAndTypeQuery(userId, type);
    }

    @Override
    public List<Ipool> findByCountryAndType(String country, Integer type) {
        return ipoolRepository.findByCountryAndType(country, type);
    }


}
